//你好
const _console = String.raw/* cpp */`
  static JSValue js_console_log(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
      for (int i = 0; i < argc; i++) {
          const char *str = JS_ToCString(ctx, argv[i]);
          if (str) {
              printf("%s", str);
              JS_FreeCString(ctx, str);
          }
          if (i != argc - 1)
              printf(" ");
      }
      printf("\r\n");
      return JS_UNDEFINED;
  }


  static void print_indent(int indent) {
      for (int i = 0; i < indent; i++) {
          putchar(' ');
      }
  }


  static void dump_value(JSContext *ctx, JSValue val, int indent) {
    if (JS_IsObject(val)) {
        if (JS_IsArray(ctx, val)) {
            // 数组
            uint32_t len;
            JSValue len_val = JS_GetPropertyStr(ctx, val, "length");
            JS_ToUint32(ctx, &len, len_val);
            JS_FreeValue(ctx, len_val);
            print_indent(indent);
            printf("[Array length=%u]\r\n", len);

            for (uint32_t i = 0; i < len; i++) {
                JSValue elem = JS_GetPropertyUint32(ctx, val, i);
                dump_value(ctx, elem, indent + 2);
                JS_FreeValue(ctx, elem);
            }
        } else {
            // 对象
            JSPropertyEnum *props;
            uint32_t plen;

            if (JS_GetOwnPropertyNames(ctx, &props, &plen, val, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0) {
                return;
            }

            print_indent(indent);
            printf("{Object with %u props}\r\n", plen);

            for (uint32_t i = 0; i < plen; i++) {
                JSAtom atom = props[i].atom;
                const char *key = JS_AtomToCString(ctx, atom);

                JSValue prop_val = JS_GetProperty(ctx, val, atom);

                print_indent(indent + 2);
                printf("%s:\r\n", key);

                dump_value(ctx, prop_val, indent + 4);

                JS_FreeCString(ctx, key);
                JS_FreeValue(ctx, prop_val);
                JS_FreeAtom(ctx, atom);
            }

            js_free(ctx, props);
        }
    } else {
        // 基础类型
        const char *str = JS_ToCString(ctx, val);
        print_indent(indent);
        printf("%s\r\n", str ? str : "[non-printable]");
        if (str) JS_FreeCString(ctx, str);
    }
}

  static JSValue js_console_dump(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
    if (argc < 1) {
      return JS_UNDEFINED;
    }
    dump_value(ctx, argv[0], 0);
    return JS_UNDEFINED;
  }
  
  static JSValue js_console_info(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {

    const char *str = JS_ToCString(ctx, argv[0]);
    printf("[%s]\n", str);
    while(true){
      if((unsigned int)(*str) == 0)break;
      printf("%d,", ((unsigned int)(*str) & 0xFF));
      str++;
    }
    printf("\n");

    JS_FreeCString(ctx, str);
    // int tag = JS_VALUE_GET_TAG(argv[0]);

    // printf("tag:%d\n", tag);

    return JS_UNDEFINED;
  }

  static JSValue js_system_flushCache(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
    refreshInsCache();
    flushDataCache();
    return JS_UNDEFINED;
  }

  static JSValue js_system_halt(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
    printf("halt\n");
    while(1);
    return JS_UNDEFINED;
  }
  
  static JSValue js_system_getFreeMem(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
      //printf("js_system_getFreeMem %d\n", (int)tlsf_get_free_size);
      int free = tlsf_get_free_size();
      //printf("free: %d\n", free);
      return JS_NewInt32(ctx, free);
  }

  void console_init() {
    JSValue console = JS_NewObject(ctx);
    JS_SetPropertyStr(ctx, console, "log", JS_NewCFunction(ctx, js_console_log, "log", 1));
    JS_SetPropertyStr(ctx, console, "dump", JS_NewCFunction(ctx, js_console_dump, "dump", 1));
    JS_SetPropertyStr(ctx, console, "info", JS_NewCFunction(ctx, js_console_info, "info", 1));
    JS_SetPropertyStr(ctx, global, "console", console);

    JSValue system = JS_NewObject(ctx);
    JS_SetPropertyStr(ctx, system, "flushCache", JS_NewCFunction(ctx, js_system_flushCache, "flushCache", 0));
    JS_SetPropertyStr(ctx, system, "halt", JS_NewCFunction(ctx, js_system_halt, "halt", 0));
    JS_SetPropertyStr(ctx, system, "getFreeMem", JS_NewCFunction(ctx, js_system_getFreeMem, "getFreeMem", 0));
    JS_SetPropertyStr(ctx, global, "system", system);

  }
`;

module.exports = { _console };